1 /*
2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021
3 License:   [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License].
4 Authors: Marcelo S. N. Mancini
5 
6 	Copyright Marcelo S. N. Mancini 2018 - 2021.
7 Distributed under the CC BY-4.0 License.
8    (See accompanying file LICENSE.txt or copy at
9 	https://creativecommons.org/licenses/by/4.0/
10 */
11 
12 module hip.api.input.gamepad;
13 
14 public import hip.api.input.button;
15 
16 enum HipGamepadAnalogs : ubyte
17 {
18     leftStick,
19     rightStick,
20     leftTrigger,
21     rightTrigger
22 }
23 
24 /** Define order is starting from up and it goes counter clockwise*/
25 enum HipGamepadButton : ubyte
26 {
27     dPadUp = 0,
28     dPadLeft,
29     dPadDown,
30     dPadRight,
31 
32     psTriangle,
33     psSquare,
34     psCross,
35     psCircle,
36 
37     xboxY = psTriangle,
38     xboxX = psSquare,
39     xboxA = psCross,
40     xboxB = psCircle,
41 
42     left1,
43     right1,
44 
45     left2,
46     right2,
47 
48     left3,
49     right3,
50 
51     start,
52     select,
53     home,
54     printScreen,
55     volumeUp,
56     volumeDown,
57 
58     ///Internal usage only
59     count
60 }
61 
62 
63 HipGamepadButton gamepadButtonFromString(string str)
64 {
65     switch(str)
66     {
67         static foreach(btn; __traits(allMembers, HipGamepadButton))
68         {
69             case btn:
70                 return __traits(getMember, HipGamepadButton, btn);
71         }
72         default:
73             return HipGamepadButton.count;
74     }
75 }
76 
77 ///Based on https://docs.microsoft.com/en-us/uwp/api/windows.system.power.batterystatus?view=winrt-20348
78 enum HipGamepadBatteryState : ubyte
79 {
80     notPresent = 0,
81     discharging,
82     idle,
83     charging,
84 }
85 ///Struct based on winrt::Windows::Devices::Power::BatteryReport
86 pragma(LDC_no_typeinfo)
87 struct HipGamepadBatteryStatus
88 {
89     int chargeRateInMilliwatts;
90     int remainingCapacityInMilliwattHours;
91     int fullChargeCapacityInMilliwattHours;
92     HipGamepadBatteryState state;
93 }
94 
95 interface IHipGamepad
96 {
97     /** Returns wether it is vibrating. Receives a time to stop vibrating */
98     bool setVibrating(float vibrationPower, float time = 0.5);
99     bool isVibrating();
100     /** Returns the Id for this controller, usually the order in which it was connected*/
101     ubyte getId();
102 
103     /** Completely implementation dependent, 
104     *   deltaTime is used for it auto stop vibrating
105     */
106     void poll(float deltaTime);
107 
108     /** Returns a Vector3 containing the current state of the analog */
109     float[3] getAnalogState(HipGamepadAnalogs analog = HipGamepadAnalogs.leftStick);
110     /** This will set a deadzone for making gamepad doesn't issue any kind of event until the threshold*/
111     void setDeadzone(float threshold = 0.1);
112 
113     /** Returns the battery status in range 0 - 1, only makes sense when wireless*/
114     float getBatteryStatus()out(r; (r > 0.0f && r <= 1.0f), "Battery should be 0 > battery <= 1");
115     /** Knowing wether it is wireless may be essential for showing battery alert */
116     bool isWireless();
117 
118 
119     /** Receives a gamepad button*/
120     bool isButtonPressed(HipGamepadButton btn);
121     bool isButtonJustPressed(HipGamepadButton btn);
122     bool isButtonJustReleased(HipGamepadButton btn);
123 
124     final bool isButtonPressed(string btn){return isButtonPressed(gamepadButtonFromString(btn));}
125     /** After first created, gamepads are never destroyed, use this property for using it or not*/
126     bool isConnected();
127 
128     /** May include an implementation for turning gamepad off*/
129     void setConnected(bool connected);
130 
131 
132 }
133 
134 abstract class AHipGamepad : IHipGamepad
135 {
136     protected float vibrationPower = 0;
137     protected float vibrationTime = 0;
138     protected bool _isConnected = false;
139     protected float deadZone = 0.1;
140     protected float aliveZone = 0.95;
141 
142     void setDeadzone(float threshold = 0.1){deadZone = threshold;}
143     void setAlivezone(float threshold = 0.95){aliveZone = threshold;}
144     bool isVibrating(){return vibrationPower==0;}
145     bool isConnected(){return _isConnected;}
146     void setConnected(bool connected){_isConnected = connected;}
147 
148 }